
class Loader
  def self.load_files files
    $files ||= {}
    files.each { |f|
      $files[f] ||= nil
    }
    files.each {|f|
      reload f
    }
  end

  def self.reload file
    $files ||= {}
    time = File.mtime(file)
    if !$files[file] || time > $files[file]
      loadfile file
      $files[file] = time
    end
  end

  def self.loadfile file
    retried = 0
    begin
      #puts "-------- loading "+file
      Kernel.load(file)
    rescue NameError => e
      if retried > 15
        raise e
      end
      #puts "\n"
      #p e.message
      if match = e.message.match(/uninitialized constant ([A-Z][A-Za-z_:]*)/)
        #p :matching, match
        missing_name = match[1]
        missing_file_name = missing_name.split('::').last.gsub(/\B[A-Z]/, '_\&').downcase
        possible_dependency_paths = []

        $files.each { |f, t|
          if f.split('/').last == missing_file_name+'.rb'
            possible_dependency_paths << f
          end
        }

        dependency_file = possible_dependency_paths.select { |f|
          File.exists? f
        }.first

        if dependency_file
          if dependency_file == file
            puts "trying to load #{missing_name} ("+dependency_file+") for #{e.backtrace[1]}"
            warn "looks like unsolvable dependence: #{file} in need of #{dependency_file}"
            return
          end
          #puts "-------- loading dependency file "+dependency_file
          loadfile dependency_file
        else
          raise "could not find dependency "+missing_name+" for #{e.backtrace[1]}"
        end
        retried += 1
        retry
      else
        raise e
      end
    end
  end
end